package com.bothin.annotation;

import com.bothin.annotation.pojo.*;

import java.lang.annotation.ElementType;
import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * Created by bothin
 * At 2020/4/12 18:04
 * Description: 测试一下常用的java反射操作
 */
public class TestRefection {

    public static void main(String[] args) throws Exception {

        theWayToGetClass();

        getAllTypeClass();

        analyze();

        TestRefectionMethods();
    }

    /**
     * 列举获取class的几种方式
     */
    public static void theWayToGetClass() throws ClassNotFoundException {
        System.out.println("+++++++++++++theWayToGetClass()++++++++++++++");
        Person person = new Person("person", 40);

        //方式一：通过对象获取
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());  //所有对象拥有同一个class hashcode

        //方式二：通过Class.forName获取
        Class<?> c2 = Class.forName("com.bothin.annotation.pojo.Student");
        System.out.println(c2.hashCode());

        //方式三：通过类名获取
        Class c3 = Student.class;
        System.out.println(c3.hashCode());

        //方式四：通过基本内置类型的包装类获取
        Class c4 = Integer.TYPE;
        System.out.println(c4.hashCode());

        //获取父类类型
        Class superclass = c1.getSuperclass();
        System.out.println(superclass);

    }

    /**
     * 获取所有类型的class对象
     * 1、只要是同一个类，都是同一个class
     * 2、只要数组的维度一样，都是同一个class
     */
    public static void getAllTypeClass(){
        System.out.println("__________________getAllTypeClass()_______________________");
        Class c1 = Object.class; //类
        Class c2 = Comparable.class; //接口
        Class c3 = String[].class; //一维数组
        Class c4 = int[][].class; //二维数组
        Class c5 = Override.class; //注解
        Class c6 = ElementType.class; //枚举
        Class c7 = Integer.class; //包装类
        Class c8 = void.class; //void
        Class c9 = Class.class; //Class

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);

    }

    /**
     * 类加载内存分析
     * 类加载器的分析
     */
    public static void analyze() throws ClassNotFoundException {
        System.out.println("=================analyze()=====================");
        A a = new A();
        System.out.println(a.m);    //100

        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader); //jdk.internal.loader.ClassLoaders$AppClassLoader@3fee733d

        //获取系统类加载器的父类加载部一>扩展类加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent); //jdk.internal.loader.ClassLoaders$PlatformClassLoader@2f4d3709

        //获取扩展类加载器的父类加载器->根加载器(C/c++)
        ClassLoader rootClassLoader = parent.getParent();
        System.out.println(rootClassLoader); //null C/c++编写，获取不到

        //测试当前类是哪个加载器加载的
        ClassLoader classLoader = Class.forName("com.bothin.annotation.TestRefection").getClassLoader();
        System.out.println(classLoader);

        //测试JDK内置类是哪个加载器加载的
        classLoader = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);

        //如何获取系统类加载可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
    }

    /**
     * 了解反射机制的相关类
     */
    public static void TestRefectionMethods() throws Exception {
        System.out.println("#############TestRefectionMethods()#############");
        //测试asSubclass()
        Teacher teacher = new Teacher(40, 10000);
        Class<? extends Teacher> teacherClass = teacher.getClass();
        Class<? extends Person> personClass = teacherClass.asSubclass(Person.class);
        Person person = personClass.getDeclaredConstructor().newInstance();
        System.out.println("测试asSubclass()："+person);

        Reflection bothin = new Reflection(1000, 20, "bothin");

        Class<? extends Reflection> bothinClass = bothin.getClass();

        //返回该类中的内部类
        System.out.println("返回该类中的公共内部类"+Arrays.toString(bothinClass.getClasses()));
        System.out.println("返回该类中的所有内部类"+Arrays.toString(bothinClass.getDeclaredClasses()));

        for (Field field : bothinClass.getFields()) {
            System.out.println(field.getType());
            System.out.println(field.getName());
            System.out.println("getGenericType()："+field.getGenericType());
            System.out.println(field.get(bothin));
//            System.out.println(field.set(bothin));
        }


    }


}

